/* {{{1
KCChess -- yet another xboard-compatible chess engine.
Copyright (C) 2006-2007 Konstantin 'KCC' Serebryany <konstantin.s.serebryany#gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

/* -------------------------------------------------------------------------------------
{{{1
This is my attempt to create a chess engine, similar to many existing 
programs like 'crafty' or 'gnuchess'. 
The major reason why I am doing this is fun.

The program is written in C++, uses state of the art bitboard approach 
to represent chess boards. However, it does not use rotating bitboards 
(like in 'crafty' or in 'gnuchess'), but uses slightly different approach
for move generation (somewhat similar to http://www.cis.uab.edu/hyatt/bitmaps.html, section 2).

Source code is portable, but has few specific parts 
that are written using __asm__ for x86_64 to speedup computations.

Current status of the program: it can play a legal game of chess using 'xboard' GUI.
It can even defeat a novice human player (e.g. me), 
but mature chess programs will crash it like a bug.
*/


//# MAINPAGE {{{1
/** @mainpage

    @author Konstantin 'KCC' Serebryany, konstantin.s.serebryany@gmail.com
    
    @section sec_intro Introduction
    This is an attempt to write my own chess engine. 
    
    @section sec_algo Algorithms
    - Bit board abstraction is implemented in class BB.
    - Chess board abstraction and move generation is implemented in class BOARD. 
         - On my Core 2 duo 1.8Ghz move generations gives 14-18 MNPS (million nodes per second).
    - Search algorithms are implemented in class DISPATCHER.
        - Currently only a very basic alpha-beta search is implemented in DISPATCHER::ab_search().
    - Evaluation function is based only on material BOARD::get_material().
    - Transposition table is implemented as classes TTE and TT.
    - Opening Game db is implemented in class OGDB.
    - Very basic xboard interface is implemented in class CLI. 

    @section sec_build Build
    Simple build can be done by 'g++ kcchess.cc -DKCChess_main=main' (it will generate very slow program). 
    For other builds refer to Makefile. 

    Best known speed was obtained on x86_64 machine with 
    @verbatim
    g++ -Wall -DDEBUG=0 -O2 -DHAVE_x86_64_asm  kcchess.cc -DKCChess_main=main
    @endverbatim
    
    @section sec_todo TODO
    - better search 
    - better move ordering
    - better evaluation function
    - parallel search 
    - update zobrist hash in BOARD::make_move() instead of computing it from scratch
    - extend xboard interface
    - end game db?
    - implement 3-repeats rule, 50-moves rule
 */


namespace KCChess{  // {{{1

#ifndef DEBUG
# define DEBUG 1
#endif

#if DEBUG >= 1
# define Assert assert
#else
# define Assert(a) 
#endif


// # ENUMS {{{1
/// Board positions 
enum{
    A8=070, B8=071, C8=072, D8=073, E8=074, F8=075, G8=076, H8=077, 
    A7=060, B7=061, C7=062, D7=063, E7=064, F7=065, G7=066, H7=067, 
    A6=050, B6=051, C6=052, D6=053, E6=054, F6=055, G6=056, H6=057, 
    A5=040, B5=041, C5=042, D5=043, E5=044, F5=045, G5=046, H5=047, 
    A4=030, B4=031, C4=032, D4=033, E4=034, F4=035, G4=036, H4=037, 
    A3=020, B3=021, C3=022, D3=023, E3=024, F3=025, G3=026, H3=027, 
    A2=010, B2=011, C2=012, D2=013, E2=014, F2=015, G2=016, H2=017, 
    A1=000, B1=001, C1=002, D1=003, E1=004, F1=005, G1=006, H1=007,


    ROW_1=0, ROW_2=1, ROW_3=2, ROW_4=3, ROW_5=4, ROW_6=5, ROW_7=6, ROW_8=7,    
    COL_A=0, COL_B=1, COL_C=2, COL_D=3, COL_E=4, COL_F=5, COL_G=6, COL_H=7,    

};

/// Chess pieces 
enum PIECE_ENUM{ 
    K = 0, ///< King
    Q = 1, ///< Queen
    R = 2, ///< Rook
    B = 3, ///< Bishop
    N = 4, ///< Knight
    P = 5, ///< Pawn
    PIECE_ERROR
};

/// Chess sides 
enum{
    L = 0, ///< LIGHT, must be 0
    D = 1, ///< DARK,  must be 1
};

 

enum {
    MAX_N_MOVES=512, ///< Max possible number of moves for one chess position
    ONE_PLY_DEPTH = 128, ///< units of depth: ONE_PLY_DEPTH is one PLY
    MAX_PLY       = 25   ///< max number of PLYs to search


};
// what is the max possible number of moves? 

//# struct PIECE {{{1

/// Nothing special, just a chess piece.
struct PIECE{
    typedef uint32_t piece_t;

    PIECE(piece_t p) : m_piece(p) {Assert(p <= P);}
    PIECE(const PIECE &p) : m_piece(p.m_piece) {}

    operator piece_t () const {return m_piece;}
private: 
    piece_t m_piece;

};

//# struct COLOR {{{1
/// Color, i.e. dark or light.
struct COLOR{
    typedef uint32_t color_t;

    COLOR(color_t c) : m_color(c) {Assert(c == L || c == D);}
    COLOR(const COLOR &c) :m_color(c.m_color) {}

    operator color_t () {return m_color;}
private:
    color_t m_color;
};

//# struct POS {{{1
typedef uint64_t pos_t;
typedef int64_t pos_off_t;

/// Position on board (0..63)
class POS{

    bool is_legal() const {return m_pos < 64;}
public: 
    POS(pos_t row, pos_t col) : m_pos(row<<3|col) {Assert(is_legal());}
    POS(pos_t p)          : m_pos(p) {Assert(is_legal());}
    POS(const POS &p)     : m_pos(p.m_pos) {}
    POS(const POS &p, pos_off_t row_sh, pos_off_t col_sh) : m_pos(p.m_pos + (row_sh*8+col_sh)) 
    {   
        Assert(p.shift_is_legal(row_sh, col_sh));
        Assert(is_legal());
    }
    
    bool shift_is_legal(pos_off_t row_sh, pos_off_t col_sh) const {return (row() + row_sh < 8) && (col() + col_sh < 8);}

    pos_t row() const {return (m_pos >> 3);}
    pos_t col() const {return m_pos & 7;}

    operator pos_t () {return m_pos;}
 
    POS reflect() const {return POS(7 - row(), col());}

private:
    pos_t m_pos;
};

//# POS: operator << {{{2
/// Print the position
inline ostream &operator << (ostream &os, POS pos)
{
    return os << (char)('A' + pos.col()) << (1 + pos.row());
}


//# struct MOVE {{{1
/// A MOVE consists of 
/// - POS from
/// - POS to 
/// - PIECE promo_piece
struct MOVE{
    typedef uint32_t move_t;

    MOVE(move_t m) :m_move(m){}
    MOVE(const MOVE &m) :m_move(m.m_move){}
    MOVE &operator = (const MOVE &m) {m_move = m.m_move; return *this;}

    MOVE(POS from, POS to) : m_move((from << 6) | to) {}
    MOVE(POS from, POS to, PIECE promo_piece) : m_move((from << 6) | to) {
        m_move |= (((move_t)promo_piece) << 12);
    }
    POS from() const {return (m_move >> 6) & 63;}
    POS to()   const {return m_move & 63;}
    PIECE get_promot_piece() const {return ((m_move >> 12) & 7);}

    void reflect(){
        m_move = MOVE(from().reflect(), to().reflect(), get_promot_piece()).raw();
    }   

    bool is_illegal() const {return m_move == 0;}
        
    move_t raw() const {return m_move;}

    bool operator == (const MOVE &m) const {return m_move == m.m_move;}
    bool operator  < (const MOVE &m) const {return m_move  < m.m_move;}

    string coordinate_notation(bool is_reflected){
        string res;
        int row1 = from().row();
        int row2 = to().row();
        if(is_reflected){
            row1 = 7 - row1;
            row2 = 7 - row2;
        }
        res += (char)from().col() + 'a';
        res += (char)row1 + '1';
        res += (char)to().col() + 'a';
        res += (char)row2 + '1';
        switch(get_promot_piece()){
                case Q: res += 'q'; break;
                case N: res += 'n'; break;
                case R: res += 'r'; break;
                case B: res += 'b'; break;
                default: ; break;
        }
        return res;
    }
private: 
    move_t m_move;
};

//# MOVE: operator << {{{2
/// Print the move
static ostream & operator << (ostream &os, MOVE move)
{
    if(move.is_illegal()){
        return os << "illegal move; ";
    }
    os << move.coordinate_notation(false);
    return os;
}

//# SCORE {{{1
typedef int32_t score_t;
/// Score is unsigned integer, only first 15 bits are used.
class SCORE{
public:
    enum {
        SCORE_K  = 10000,
        SCORE_Q  = 128*9,
        SCORE_R  = 128*5,
        SCORE_B  = 128*3,
        SCORE_N  = 128*3,
        SCORE_BN = 128*3,
        SCORE_P  = 128 
    };
    enum {
        MAX = (1 << 14) - 1, ///< White wins
        MIN = -MAX,          ///< Black wins
        MED = 0              ///< Draw or parity 
    };

    static const score_t piece_score_arr[6];

    static score_t piece_score(PIECE p){
        return piece_score_arr[p];
    }

    SCORE(score_t score) : m_score(score) 
    {
        Assert(score <= MAX && score >= MIN);
    }
    operator score_t () {return m_score;}
private:
    score_t m_score;
};


inline ostream &operator << (ostream &os, SCORE score){
    if(score == SCORE::MAX){
        os << "MAX";
    }else if(score == SCORE::MIN){
        os << "MIN";
    }else{
        os << score_t(score);
    }
    return os;

}

//# class BB {{{1
/// 64-bit unsigned integer type
typedef uint64_t bb_t;

#if 0
inline void memcpy_10x8(bb_t *dst, const bb_t *src, size_t unused)
{
    // I tried SSE to speedup memcpy. No result.
    __asm__ ( 
            "movdqa 0x00(%1), %%xmm0 \n" 
            "movdqa %%xmm0, 0x00(%0) \n" 
            "movdqa 0x10(%1), %%xmm1 \n" 
            "movdqa %%xmm1, 0x10(%0) \n" 
            "movdqa 0x20(%1), %%xmm2 \n" 
            "movdqa %%xmm2, 0x20(%0) \n" 
            "movdqa 0x30(%1), %%xmm3 \n" 
            "movdqa %%xmm3, 0x30(%0) \n" 
            "movdqa 0x40(%1), %%xmm4 \n" 
            "movdqa %%xmm4, 0x40(%0) \n" 
            : 
            : "q" (dst), "r" (src) 
            : "memory",  "st");

}
#else
/// Some versions of gcc fail to inline/unroll memcpy(a,b,80) properly
inline void memcpy_10x8(bb_t *dst, const bb_t *src, size_t unused)
{
    bb_t t0 = src[0];
    bb_t t1 = src[1];
    bb_t t2 = src[2];
    bb_t t3 = src[3];
    bb_t t4 = src[4];
    bb_t t5 = src[5];
    bb_t t6 = src[6];
    bb_t t7 = src[7];
    bb_t t8 = src[8];
    bb_t t9 = src[9];

    dst[0] = t0;
    dst[1] = t1;
    dst[2] = t2;
    dst[3] = t3;
    dst[4] = t4;
    dst[5] = t5;
    dst[6] = t6;
    dst[7] = t7;
    dst[8] = t8;
    dst[9] = t9;


}
#endif

//# NAIVE {{{2
static inline  bb_t POPCNT(bb_t a);
//# POPCNT_NAIVE {{{3
inline bb_t POPCNT_NAIVE(bb_t a)
{
    pos_t res = 0;
    while(a) {
        res++;
        a &= a - 1;
    }
    return res; 
}
//# REFLECT_NAIVE {{{3
inline bb_t REFLECT_NAIVE(bb_t t)
{
    bb_t r0 = (t >> (7*8)) & 255;
    bb_t r1 = (t >> (6*8)) & 255;
    bb_t r2 = (t >> (5*8)) & 255;
    bb_t r3 = (t >> (4*8)) & 255;
    bb_t r4 = (t >> (3*8)) & 255;
    bb_t r5 = (t >> (2*8)) & 255;
    bb_t r6 = (t >> (1*8)) & 255;
    bb_t r7 = (t >> (0*8)) & 255;

    return 0 
        | (r0 << (0*8))
        | (r1 << (1*8))
        | (r2 << (2*8))
        | (r3 << (3*8))
        | (r4 << (4*8))
        | (r5 << (5*8))
        | (r6 << (6*8))
        | (r7 << (7*8))
        ;
}
//# FIRST_ONE_NAIVE {{{3
inline bb_t FIRST_ONE_NAIVE(bb_t x)
{
    return POPCNT(((x-1) & (~x)));
}
//# LAST_ONE_NAIVE {{{3
inline bb_t LAST_ONE_NAIVE(bb_t x)
{
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x |= x >> 32;
    return POPCNT(x) - 1;
}
//# BIT_CLEAR_NAIVE() {{{3
inline bb_t BIT_CLEAR_NAIVE(bb_t word, bb_t bit)
{
    return word & ~(1ULL << bit);
}
//# BIT_SET_NAIVE() {{{3
inline bb_t BIT_SET_NAIVE(bb_t word, bb_t bit)
{
    return word | (1ULL << bit);
}
//# BIT_TEST_NAIVE {{{3
inline bb_t BIT_TEST_NAIVE(bb_t word, bb_t bit)
{
    return (word >> bit) & 1;
}


//# IA64 with _m64_popcnt {{{2
#ifdef HAVE_m64_popcnt
# include "ia64intrin.h"
inline bb_t POPCNT(bb_t a)    {    return _m64_popcnt(a);     }
inline bb_t REFLECT(bb_t a)   {    return REFLECT_NAIVE(a);   }
inline bb_t FIRST_ONE(bb_t a) {    return FIRST_ONE_NAIVE(a); }
inline bb_t LAST_ONE(bb_t a)  {    return LAST_ONE_NAIVE(a);  }
inline bb_t BIT_CLEAR(bb_t word, bb_t bit)  { return    BIT_CLEAR_NAIVE(word, bit);}
inline bb_t BIT_SET  (bb_t word, bb_t bit)  { return    BIT_SET_NAIVE(word, bit);}
inline bb_t BIT_TEST (bb_t word, bb_t bit)  { return    BIT_TEST_NAIVE(word, bit);}

//# x86_64 with __asm__ {{{2
#elif defined(HAVE_x86_64_asm)
static inline bb_t BSF64(bb_t word)
{
      __asm__("bsfq %1,%0":"=r" (word):"r" (word));
      return word;
}

static inline bb_t BSR64(bb_t word)
{
      __asm__("bsrq %1,%0":"=r" (word):"r" (word));
      return word;
}

static inline bb_t BSWAP64(bb_t word)
{
      __asm__("bswapq %0" : "=r" (word) : "0" (word));
      return word;
}


inline bb_t POPCNT(bb_t a)    {    return POPCNT_NAIVE(a);   } 
inline bb_t REFLECT(bb_t a)   {    return BSWAP64(a);        }
inline bb_t FIRST_ONE(bb_t a) {    return BSF64(a);          }
//inline bb_t FIRST_ONE(bb_t a) {    return __builtin_ctzl(a);        } // this one seems to work as well
inline bb_t LAST_ONE(bb_t a)  {    return BSR64(a);          }

// can we use BTQ? 
inline bb_t BIT_TEST (bb_t word, bb_t bit)  { return    BIT_TEST_NAIVE(word, bit);}
#if 1 
// BT/BTS/BTR/BTC are very slow on some implementations of x86_64, but on my machine they are fast.
static inline bb_t BTR64(bb_t word, bb_t bit)
{
      __asm__ ("btrq %1,%0" : "=r" (word)  : "r" (bit) , "0" (word) );
      return word;
}
static inline bb_t BTS64(bb_t word, bb_t bit)
{
      __asm__ ("btsq %1,%0" : "=r" (word)  : "r" (bit) , "0" (word) );
      return word;
}


inline bb_t BIT_CLEAR(bb_t word, bb_t bit)  { return    BTR64(word, bit);}
inline bb_t BIT_SET  (bb_t word, bb_t bit)  { return    BTS64(word, bit);}
#else
inline bb_t BIT_CLEAR(bb_t word, bb_t bit)  { return    BIT_CLEAR_NAIVE(word, bit);}
inline bb_t BIT_SET  (bb_t word, bb_t bit)  { return    BIT_SET_NAIVE(word, bit);}
#endif
//# x86 with __asm__ {{{2
#elif defined(HAVE_x86_asm)
inline uint32_t BSF32(uint32_t word)
{
      __asm__("bsf %1,%0":"=r" (word):"r" (word));
      return word;
}

inline uint32_t BSR32(uint32_t word)
{
      __asm__("bsr %1,%0":"=r" (word):"r" (word));
      return word;
}

inline uint32_t BSWAP32(uint32_t word)
{
      __asm__ ("bswap %0":"=r" (word) : "0" (word));
      return word;
}

inline bb_t POPCNT(bb_t a)    {    return POPCNT_NAIVE(a);    } 
inline bb_t REFLECT(bb_t a)   
{
    
    uint32_t p1 = (uint32_t)(a); 
    uint32_t p2 = (uint32_t)(a >> 32);
    uint32_t p1_s = BSWAP32(p1);
    uint32_t p2_s = BSWAP32(p2);
    bb_t res = (((bb_t)p1_s) << 32) | (bb_t)p2_s;
    return res;
}
inline bb_t FIRST_ONE(bb_t a) 
{
    bb_t res;
    uint32_t p1 = (uint32_t)(a); 
    uint32_t p2 = (uint32_t)(a >> 32);
    if(p1){
        res = BSF32(p1);
    }else{
        res =  32 + BSF32(p2);
    }
    return res;
    
}
inline bb_t LAST_ONE(bb_t a)
{
    bb_t res;
    uint32_t p1 = (uint32_t)(a); 
    uint32_t p2 = (uint32_t)(a >> 32);
    if(p2){
        res = 32 + BSR32(p2);
    }else{
        res =  BSR32(p1);
    }
    return res;
    
}
inline bb_t BIT_CLEAR(bb_t word, bb_t bit)  { return    BIT_CLEAR_NAIVE(word, bit);}
inline bb_t BIT_SET  (bb_t word, bb_t bit)  { return    BIT_SET_NAIVE(word, bit);}
inline bb_t BIT_TEST (bb_t word, bb_t bit)  { return    BIT_TEST_NAIVE(word, bit);}
//# No native support for bit operations {{{2
#else
inline bb_t POPCNT(bb_t a)                   {    return POPCNT_NAIVE(a);    } 
inline bb_t REFLECT(bb_t a)                  {    return REFLECT_NAIVE(a);   }
inline bb_t FIRST_ONE(bb_t a)                {    return FIRST_ONE_NAIVE(a); }
inline bb_t LAST_ONE(bb_t a)                 {    return LAST_ONE_NAIVE(a);  }
inline bb_t BIT_CLEAR(bb_t word, bb_t bit)  { return    BIT_CLEAR_NAIVE(word, bit);}
inline bb_t BIT_SET  (bb_t word, bb_t bit)  { return    BIT_SET_NAIVE(word, bit);}
inline bb_t BIT_TEST (bb_t word, bb_t bit)  { return    BIT_TEST_NAIVE(word, bit);}
#endif



//# BB {{{2
/**
    class BB: Bitboard abstraction.
    The most important bitwise operations are implemented in CPU-dependant functions: 
    - POPCNT()
    - REFLECT()
    - FIRST_ONE()
    - LAST_ONE()
    - BIT_CLEAR()
    - BIT_SET()
    - BIT_TEST()

*/
class BB{
private:
    bb_t m_bb;
public:
#if DEBUG >= 1
    BB() : m_bb(0xDEADBEEF){}
#else
    BB() {} // we need to have an empty ctor, otherwise ctors will be called for arrays of BB
#endif
    BB (bb_t b)  : m_bb(b) {}
    BB (const BB &b) : m_bb(b.m_bb) {}

    bb_t test(POS p) const  {return BIT_TEST(m_bb, p);}
    void set(POS p)         {m_bb = BIT_SET  (m_bb, p);}
    void clear(POS p)       {m_bb = BIT_CLEAR(m_bb, p);}
    pos_t popcnt()      const  {return POPCNT(m_bb);}
    pos_t first_one()   const  {return FIRST_ONE(m_bb);}
    pos_t last_one()    const  {return LAST_ONE(m_bb);}
    BB    reflect()     const  {return REFLECT(m_bb);}
    bool  empty()       const  {return m_bb == 0;}

    void clear()   {m_bb = 0;}

    /// get 'size' bits starting from 'p'
    bb_t get(size_t p, size_t size) const{
        Assert(p + size <= 64);
        bb_t mask = ((1ULL << size) - 1);
        return (m_bb >> p) & mask;
    }

    /// put 'size' bits stored in 'val' starting from 'p'
    void put(size_t p, size_t size, bb_t val) {
        Assert(p + size <= 64);
        Assert(val < (1ULL << size));
        bb_t mask = ((1ULL << size) - 1) << p;
        m_bb = (m_bb & ~mask) | (val << p);
    }

    bb_t operator [] (POS p) const{    return test(p);}

    BB operator >> (pos_t sh) const {return m_bb >> sh;}
    BB operator << (pos_t sh) const {return m_bb << sh;}
    BB operator | (BB b) const  {return m_bb | b.m_bb;}
    BB operator |= (BB b)  {m_bb |= b.m_bb; return *this;}
    BB operator & (BB b) const  {return m_bb & b.m_bb;}
    BB operator &= (BB b)  {m_bb &= b.m_bb; return *this;}
    BB operator ~ () const {return ~m_bb;}
    bool operator == (BB b) {return m_bb == b.m_bb;}

    inline POS pop_first_one() { POS res = first_one();   clear(res);   return res;}

    operator bb_t () const {return m_bb;}

    
    // I/O
    template <class ITER>
    static ostream &show_boards(ostream &os, ITER beg, ITER end){
        for(int row = 7; row >= 0; row--){
            for(ITER i = beg; i != end; ++i){
                for(int col = 0; col < 8; col++){
                    os << ((*i)[POS(row,col)] ? 'X' : '.');
                }
                os << "  ";
            }
            os << endl;
        }
        return os;
    }
    
    ostream &show_board(ostream &os) const{
        BB ar[1] = {*this};
        return show_boards(os, ar, ar+1);
    };

    void write(ofstream &os){
        os.write((char*)&m_bb, sizeof(m_bb));
    }
};

//# BB: operator << {{{2
inline ostream &operator << (ostream &os, BB bb)
{
    return bb.show_board(os);
}

//# class BOARD {{{1


/**
  class BOARD: representation of the chess board.

  Bitboards m_color_bb[{D,L}] represent current positions of dark and light pieces. 
  Bitboards m_piece_bb[{K, ..., P}] represent current positions of pieces K, ..., P. 

  To get all dark rooks, you need to compute m_color_bb[D] | m_piece_bb[R].
  

  The side to move is always light. 
  We use BOARD::reflect_in_place() to change sides. 
  If m_is_reflected is set, actuall side to move is dark.

*/

class BOARD{
    BB m_color_bb[2];
    BB m_piece_bb[6];

    score_t m_material; // 32

    

    /// 4 bits are meaningful:
    /// - 0 for white king-side castling
    /// - 1 for white queen-side castling
    /// - 2 for black king-side castling
    /// - 3 for black queen-size castling
    class castling_info_t{ 
        uint8_t info; 
        public:
        unsigned int  L_K()  const {return info & 1;}
        unsigned int  L_Q()  const {return info & 2;}
        unsigned int  L_KQ() const {return info & 3;}
        unsigned int  D_K()  const {return info & 4;}
        unsigned int  D_Q()  const {return info & 8;}
        unsigned int  raw()  const {return info;}
        void           set_L_K()    {info |= 1;}
        void           set_L_Q()    {info |= 2;}
        void           set_D_K()    {info |= 4;}
        void           set_D_Q()    {info |= 8;}
        void           clear_L_K()  {info &= ~1;}
        void           clear_L_Q()  {info &= ~2;}
        void           clear_L_KQ() {info &= ~3;}
        void           clear_D_K()  {info &= ~4;}
        void           clear_D_Q()  {info &= ~8;}
        void reflect() {info = ((info & 3 ) << 2) | (info >> 2);}
    }m_castling_info;
    

    
    bool m_has_en_passant        :1; 
    unsigned m_en_passant_column :3;

    bool m_is_reflected          :1;
    
    BB unused;
public:    
    BB enemy_bb()                  const {return m_color_bb[D];}
    BB ally_bb ()                  const {return m_color_bb[L];}
    BB piece_bb(PIECE piece)       const {return m_piece_bb[piece];}
    BB ally_piece_bb(PIECE piece)  const {return ally_bb() & piece_bb(piece);}
    BB enemy_piece_bb(PIECE piece) const {return enemy_bb() & piece_bb(piece);}
    BB occupied_bb()               const {return ally_bb() | enemy_bb();}

    
    bool get_occupied(POS pos) const {return occupied_bb()[pos];}

    COLOR  get_color(POS pos)    const {
        Assert(get_occupied(pos)); 
        return enemy_bb()[pos]; // trick
    }
    
    
    
    PIECE  get_piece(POS pos)        const{
        Assert(get_occupied(pos));
        if(piece_bb(P)[pos]) return P;
        if(piece_bb(R)[pos]) return R;
        if(piece_bb(B)[pos]) return B;
        if(piece_bb(N)[pos]) return N;
        if(piece_bb(Q)[pos]) return Q;
        Assert(piece_bb(K)[pos]);
        return K;
    }
 
    
    PIECE  get_piece_no_K(POS pos)        const{
        Assert(get_occupied(pos));
        if(piece_bb(P)[pos]) return P;
        if(piece_bb(R)[pos]) return R;
        if(piece_bb(B)[pos]) return B;
        if(piece_bb(N)[pos]) return N;
        Assert(piece_bb(Q)[pos]);
        return Q;
    }


public: 
 
    // make explicit ctors for performance   
    BOARD() {}
    BOARD(const BOARD &b) { memcpy_10x8((bb_t*)this, (bb_t*)&b, sizeof(BOARD)); }
    BOARD & operator = (const BOARD &b) 
    {
        memcpy_10x8((bb_t*)this, (bb_t*)&b, sizeof(BOARD));
        return *this;
    }

    BOARD(const BOARD &b, MOVE move){
        b.make_move(*this, move);
    }

    bool operator == (const BOARD &b) const{
        return memcmp(this, &b, sizeof(*this)) == 0; 
    }
    bool operator < (const BOARD &b) const{
        return memcmp(this, &b, sizeof(*this)) < 0; 
    }


    bool is_reflected() const {return m_is_reflected;}

    static const char *startpos_fen() 
    {return "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -";}

    void clear() { memset((void*)this, 0, sizeof(*this));}
    bool read_fen(const string &fen, string &rest_of_string);
    bool read_fen(const string &fen) {string t; return read_fen(fen, t);}
    void set_new_game() {read_fen(startpos_fen());}
    static int char_to_piece(int c);
    static COLOR char_to_color(int c);
    static int piece_to_char(PIECE piece, COLOR color);

    void set_piece(POS pos, PIECE piece, COLOR color);


    // ----------- EVAL ------------
    SCORE eval_material() const;
    SCORE get_material()  const {Assert(m_material < SCORE::MAX); return m_material;}
    SCORE evaluate(score_t alpha, score_t beta) const;
    inline score_t evaluate_bonus() const;
    score_t evaluate_pawns() const;
    score_t evaluate_mobility() const;
    inline score_t evaluate_pure_pawns(BB pawns, BB enemy_pawns) const;

    // ----------- GEN --------------

    inline BB gen_castling() const;
    inline BB mobility_R(POS pos) const;
    inline BB mobility_B(POS pos) const;
    inline BB mobility_Q(POS pos) const;
    inline BB mobility_N(POS pos) const;
    inline BB mobility_K(POS pos) const;
    inline BB mobility_P(POS pos) const;

    inline int64_t mobility_count_R(POS pos) const;
    inline int64_t mobility_count_B(POS pos) const;
    inline int64_t mobility_count_Q(POS pos) const;
    inline int64_t mobility_count_N(POS pos) const;
    

    
    inline 
        BB attackers(POS pos) const;
    inline 
        BB enemy_attackers(POS pos) const;
    inline 
        BB ally_attackers(POS pos)  const;

    BB enemy_K_is_attacked() const {return ally_attackers (enemy_piece_bb(K).first_one());}
    BB ally_K_is_attacked()  const {return enemy_attackers(ally_piece_bb(K).first_one());}
    

    bb_t zobrist_hash  (const bb_t random_values[]) const;
    bb_t zobrist_hash  () const;

    bool is_draw_by_material() const;
    
    inline 
    void make_move(BOARD &res, PIECE from_piece, POS from, POS to, PIECE promo) const;

    void make_move(BOARD &res, MOVE move) const;
    void make_move_in_place(MOVE move){
        BOARD t;
        make_move(t, move);
        *this = t;
    }


    template <class GEN_MOVE_ACTION> 
    size_t gen_moves(GEN_MOVE_ACTION &action) const;

    /// return true if 'move' is a legal move 
    bool is_legal_move(MOVE move) const;

    bool is_pseudo_move(MOVE move) const;

    void reflect_in_place();

    void clear_reflected() {m_is_reflected = false;}
    void set_reflected()   {m_is_reflected = true;}

    void clear_en_passant() {m_has_en_passant = false; m_en_passant_column = 0;}


    MOVE parse_SAN(const string &SAN) const;
    ostream &make_SAN(ostream &os, MOVE move) const;

    string fen() const;

// -------- I/O    -------
    template <class ITER> 
    static ostream &show_boards(ostream &os, ITER beg, ITER end);

    ostream &show_board(ostream &os) const;


    
}; // ------------

//# GEN_MOVE_ACTION_STORE {{{1
/**
    Action type for BOARD::gen_moves(): store all pseudo moves
  */
class GEN_MOVE_ACTION_STORE{
    MOVE::move_t pseudo_moves[MAX_N_MOVES];
public:
    /// register the pseudo move. return false to indicate that we continue generating moves 
    bool operator()(const BOARD &board, size_t n, POS from, POS to, PIECE promo, PIECE piece, POS K_pos){
        pseudo_moves[n] = MOVE(from, to, promo).raw();
        return false;
    }

    BB mask_target(BB b)    {return b;} ///< ident 
    bool allow_promo()      {return true;}
    bool allow_en_passant() {return true;}

    MOVE::move_t operator[] (size_t n){
        return pseudo_moves[n];
    }
    MOVE::move_t *raw(){
        return pseudo_moves;
    }
};


#undef Assert
}  // namespace KCChess

// END {{{1   
// vim:shiftwidth=4:softtabstop=4:expandtab:foldmethod=marker
